/*

一个驱动兼容多个设备的实现

*/


#include <linux/module.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define BUFF 32 

struct device_struct{

    //设备号
    dev_t dev_num;
    //主设备号
    int major;
    //次设备号
    int minor;

    //cdev
    struct cdev cdev_test;
    //class
    struct class* class;
    //设备
    struct device* device;
    //内容
    char kbuf[BUFF] ;
};



//定义dev1 dev2 设备
struct device_struct dev1 = {.kbuf = "nodata"};
struct device_struct dev2 = {.kbuf = "nodata"};;

//open
static int dev_open(struct inode* inode, struct file* filp)
{
   
    //根据inode找到设备在file中设置文件私有数据
    filp->private_data = container_of(inode->i_cdev, struct device_struct, cdev_test);
    printk(KERN_EMERG "dev_open\n");
    return 0;


}

//write
static ssize_t dev_write(struct file* filp, const char __user* buf, size_t size, loff_t* off)
{
    //拿到device_struct 对象指针
    struct device_struct* dev = (struct device_struct*)filp->private_data;
    printk(KERN_EMERG "dev_minor: %d\n", dev->minor);

    if (size > sizeof(dev->kbuf))
    {
        printk(KERN_EMERG "size over\n");
        return -EINVAL;
    }
    if (copy_from_user(dev->kbuf, buf, size) != 0)
    {
        printk(KERN_EMERG "write failed\n");
        return -EFAULT;
    }

    printk(KERN_EMERG "write content: %s\n", dev->kbuf);
    return size;
}

//read
static ssize_t dev_read(struct file* filp, char __user* buf, size_t size,loff_t* off )
{
    struct device_struct* dev = (struct device_struct*)filp->private_data;
    if (size > sizeof(dev->kbuf))
    {
        size = sizeof(dev->kbuf);
    }
    if(copy_to_user(buf, dev->kbuf, size) != 0)
    {
        printk(KERN_EMERG "read failed \n");
        return -EFAULT;
    }
    printk(KERN_EMERG "read content: %s \n", dev->kbuf);
    return size;
}

//release
static int dev_release(struct inode* inode, struct file* filp)
{
    printk(KERN_EMERG "release \n");
    return 0;
}

//file_ops
struct file_operations dev_ops ={
    .owner = THIS_MODULE,
    .open  = dev_open,
    .read  = dev_read,
    .write = dev_write,
    .release = dev_release

};

//驱动入口函数
static int __init multi_init(void)
{
    //忽略接口调用失败的情况
    //注册字符设备驱动
    int ret = 0;
    ret = alloc_chrdev_region(&dev1.dev_num, 0, 2, "dev");
    //设置dev2的dev_num
    dev2.dev_num = dev1.dev_num + 1;
    printk(KERN_EMERG "alloc_chrdev_region sucess \n");

    //设置主次设备号并打印
    dev1.major = MAJOR(dev1.dev_num);
    dev1.minor = MINOR(dev1.dev_num);
    printk(KERN_EMERG "dev1 major %d\n", dev1.major);
    printk(KERN_EMERG "dev1 minor %d\n", dev1.minor);

    dev2.major = MAJOR(dev2.dev_num);
    dev2.minor = MINOR(dev2.dev_num);
    printk(KERN_EMERG "dev2 major %d\n", dev2.major);
    printk(KERN_EMERG "dev2 minor %d\n", dev2.minor);


    //初始化dev
    dev1.cdev_test.owner = THIS_MODULE;
    dev2.cdev_test.owner = THIS_MODULE;
    cdev_init(&dev1.cdev_test, &dev_ops);
    cdev_init(&dev2.cdev_test, &dev_ops);

    //添加dev 到内核
    cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
    cdev_add(&dev2.cdev_test, dev2.dev_num, 1);

    //创建类
    dev1.class = class_create(THIS_MODULE, "dev1_class");
    dev2.class = class_create(THIS_MODULE, "dev2_class");

    //创建设备
    dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "dev1");
    dev2.device = device_create(dev2.class, NULL, dev2.dev_num, NULL, "dev2");

    return 0;    
}


static void __exit multi_exit(void)
{
    //注销
    unregister_chrdev_region(dev1.dev_num, 2);
    
    //删除cdev
    cdev_del(&dev1.cdev_test);
    cdev_del(&dev2.cdev_test);

    //删除设备
    device_destroy(dev1.class, dev1.dev_num);
    device_destroy(dev2.class, dev2.dev_num);

    //删除类
    class_destroy(dev1.class);
    class_destroy(dev2.class);
    
}

module_init(multi_init);
module_exit(multi_exit)
 
MODULE_LICENSE("GPL");